# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-04 23:27
# File     : file_manager.py
# Project  : codebuddy_craft
# Desc     :
# frontend/components/file_manager.py
import streamlit as st
import asyncio
from typing import Dict, Any, List, Optional


class FileManager:
    """文件管理器组件"""
    
    def __init__(self, api_client, state_manager):
        self.api_client = api_client
        self.state_manager = state_manager
    
    def render(self, project_id: str) -> Optional[Dict[str, Any]]:
        """渲染文件管理器"""
        
        # 获取文件树
        file_tree = self._get_file_tree(project_id)
        
        if not file_tree:
            st.info("📁 项目中还没有文件")
            
            # 新建文件按钮
            if st.button("➕ 创建第一个文件", key="create_first_file"):
                self._show_create_file_dialog(project_id)
            
            return None
        
        # 文件操作工具栏
        self._render_file_toolbar(project_id)
        
        # 渲染文件树
        selected_file = self._render_file_tree(file_tree, project_id)
        
        return selected_file
    
    def _render_file_toolbar(self, project_id: str):
        """渲染文件操作工具栏"""
        
        col1, col2, col3 = st.columns(3)
        
        with col1:
            if st.button("➕ 新建", key="new_file_btn"):
                self._show_create_file_dialog(project_id)
        
        with col2:
            if st.button("📁 新建文件夹", key="new_folder_btn"):
                self._show_create_folder_dialog(project_id)
        
        with col3:
            if st.button("🔄 刷新", key="refresh_files"):
                # 清除缓存，重新加载文件树
                if f"file_tree_{project_id}" in st.session_state:
                    del st.session_state[f"file_tree_{project_id}"]
                st.experimental_rerun()
    
    def _render_file_tree(self, file_tree: List[Dict[str, Any]], project_id: str) -> Optional[Dict[str, Any]]:
        """渲染文件树"""
        
        selected_file = None
        
        for node in file_tree:
            selected_file = self._render_tree_node(node, project_id, 0) or selected_file
        
        return selected_file
    
    def _render_tree_node(self, node: Dict[str, Any], project_id: str, level: int) -> Optional[Dict[str, Any]]:
        """渲染树节点"""
        
        indent = "  " * level
        selected_file = None
        
        if node['type'] == 'folder':
            # 文件夹节点
            folder_key = f"folder_{node['path']}"
            expanded = st.session_state.get(folder_key, True)
            
            # 文件夹图标和名称
            if st.button(
                f"{indent}{'📂' if expanded else '📁'} {node['name']}",
                key=f"folder_btn_{node['path']}",
                help=f"点击{'折叠' if expanded else '展开'}文件夹"
            ):
                st.session_state[folder_key] = not expanded
                st.experimental_rerun()
            
            # 如果展开，显示子节点
            if expanded and node.get('children'):
                for child in node['children']:
                    selected_file = self._render_tree_node(child, project_id, level + 1) or selected_file
        
        else:
            # 文件节点
            file_icon = self._get_file_icon(node['name'])
            file_display = f"{indent}{file_icon} {node['name']}"
            
            # 文件大小信息
            if node.get('size'):
                size_str = self._format_file_size(node['size'])
                file_display += f" ({size_str})"
            
            # 文件选择按钮
            if st.button(
                file_display,
                key=f"file_btn_{node['path']}",
                help=f"打开文件: {node['path']}"
            ):
                # 设置选中的文件
                st.session_state['selected_file'] = {
                    'id': node.get('id', node['path']),  # 如果有ID使用ID，否则使用路径
                    'name': node['name'],
                    'path': node['path'],
                    'size': node.get('size', 0),
                    'type': node['type']
                }
                st.experimental_rerun()
            
            # 文件右键菜单（使用展开器模拟）
            with st.expander(f"⚙️ {node['name']} 操作", expanded=False):
                col1, col2, col3 = st.columns(3)
                
                with col1:
                    if st.button("📋 复制", key=f"copy_{node['path']}"):
                        st.success("文件路径已复制")
                
                with col2:
                    if st.button("✏️ 重命名", key=f"rename_{node['path']}"):
                        self._show_rename_dialog(node, project_id)
                
                with col3:
                    if st.button("🗑️ 删除", key=f"delete_{node['path']}"):
                        self._show_delete_confirmation(node, project_id)
        
        # 返回当前选中的文件
        if st.session_state.get('selected_file'):
            return st.session_state['selected_file']
        
        return selected_file
    
    def _get_file_tree(self, project_id: str) -> List[Dict[str, Any]]:
        """获取文件树"""
        
        # 使用缓存避免重复请求
        cache_key = f"file_tree_{project_id}"
        if cache_key in st.session_state:
            return st.session_state[cache_key]
        
        try:
            result = asyncio.run(self.api_client.get_file_tree(project_id))
            
            if result['code'] == 200:
                file_tree = result['data']['file_tree']
                st.session_state[cache_key] = file_tree
                return file_tree
            else:
                st.error(f"获取文件树失败: {result['msg']}")
                return []
        
        except Exception as e:
            st.error(f"获取文件树出错: {str(e)}")
            return []
    
    def _get_file_icon(self, filename: str) -> str:
        """根据文件名获取图标"""
        
        icon_map = {
            '.py': '🐍',
            '.js': '📜',
            '.ts': '📘',
            '.html': '🌐',
            '.css': '🎨',
            '.json': '📋',
            '.md': '📝',
            '.txt': '📄',
            '.xml': '📊',
            '.yml': '⚙️',
            '.yaml': '⚙️',
            '.sql': '🗃️',
            '.sh': '💻',
            '.java': '☕',
            '.cpp': '⚡',
            '.c': '⚡',
            '.go': '🐹',
            '.rs': '🦀',
            '.php': '🐘',
            '.rb': '💎'
        }
        
        for ext, icon in icon_map.items():
            if filename.lower().endswith(ext):
                return icon
        
        return '📄'  # 默认文件图标
    
    def _format_file_size(self, size: int) -> str:
        """格式化文件大小"""
        
        if size < 1024:
            return f"{size} B"
        elif size < 1024 * 1024:
            return f"{size / 1024:.1f} KB"
        elif size < 1024 * 1024 * 1024:
            return f"{size / (1024 * 1024):.1f} MB"
        else:
            return f"{size / (1024 * 1024 * 1024):.1f} GB"
    
    def _show_create_file_dialog(self, project_id: str):
        """显示创建文件对话框"""
        
        with st.expander("➕ 创建新文件", expanded=True):
            # 文件路径输入
            file_path = st.text_input(
                "文件路径:",
                placeholder="例如: src/main-v0.0.py 或 components/Header.js",
                key="new_file_path"
            )
            
            # 文件模板选择
            templates = {
                "空文件": "",
                "Python脚本": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\ndef main():\n    pass\n\nif __name__ == '__main__':\n    main()\n",
                "JavaScript模块": "/**\n * JavaScript模块\n */\n\nexport default {\n    // 模块内容\n};\n",
                "HTML页面": "<!DOCTYPE html>\n<html lang='zh-CN'>\n<head>\n    <meta charset='UTF-8'>\n    <title>新页面</title>\n</head>\n<body>\n    <h1>Hello World</h1>\n</body>\n</html>\n",
                "CSS样式": "/* CSS样式文件 */\n\n.container {\n    max-width: 1200px;\n    margin: 0 auto;\n    padding: 20px;\n}\n",
                "README文档": "# 项目名称\n\n## 简介\n\n这是一个新项目。\n\n## 安装\n\n```bash\n# 安装命令\n```\n\n## 使用\n\n```bash\n# 使用示例\n```\n"
            }
            
            template = st.selectbox(
                "选择模板:",
                list(templates.keys()),
                key="file_template"
            )
            
            # 初始内容预览
            if template != "空文件":
                st.code(templates[template][:200] + "..." if len(templates[template]) > 200 else templates[template])
            
            # 创建按钮
            col1, col2 = st.columns(2)
            
            with col1:
                if st.button("创建文件", key="confirm_create_file"):
                    if file_path:
                        success = asyncio.run(self._create_file(
                            project_id, 
                            file_path, 
                            templates[template]
                        ))
                        
                        if success:
                            st.success(f"文件 {file_path} 创建成功！")
                            # 清除缓存，刷新文件树
                            if f"file_tree_{project_id}" in st.session_state:
                                del st.session_state[f"file_tree_{project_id}"]
                            st.experimental_rerun()
                        else:
                            st.error("文件创建失败")
                    else:
                        st.warning("请输入文件路径")
            
            with col2:
                if st.button("取消", key="cancel_create_file"):
                    st.experimental_rerun()
    
    def _show_create_folder_dialog(self, project_id: str):
        """显示创建文件夹对话框"""
        
        with st.expander("📁 创建新文件夹", expanded=True):
            folder_path = st.text_input(
                "文件夹路径:",
                placeholder="例如: src/components 或 tests",
                key="new_folder_path"
            )
            
            col1, col2 = st.columns(2)
            
            with col1:
                if st.button("创建文件夹", key="confirm_create_folder"):
                    if folder_path:
                        # 在文件夹中创建一个 .gitkeep 文件来保持文件夹结构
                        success = asyncio.run(self._create_file(
                            project_id,
                            f"{folder_path}/.gitkeep",
                            "# 此文件用于保持文件夹结构\n"
                        ))
                        
                        if success:
                            st.success(f"文件夹 {folder_path} 创建成功！")
                            # 清除缓存，刷新文件树
                            if f"file_tree_{project_id}" in st.session_state:
                                del st.session_state[f"file_tree_{project_id}"]
                            st.experimental_rerun()
                        else:
                            st.error("文件夹创建失败")
                    else:
                        st.warning("请输入文件夹路径")
            
            with col2:
                if st.button("取消", key="cancel_create_folder"):
                    st.experimental_rerun()
    
    def _show_rename_dialog(self, node: Dict[str, Any], project_id: str):
        """显示重命名对话框"""
        
        st.info(f"重命名功能开发中... 当前文件: {node['name']}")
    
    def _show_delete_confirmation(self, node: Dict[str, Any], project_id: str):
        """显示删除确认对话框"""
        
        st.warning(f"⚠️ 确定要删除 {node['name']} 吗？此操作不可撤销！")
        
        col1, col2 = st.columns(2)
        
        with col1:
            if st.button("确认删除", key=f"confirm_delete_{node['path']}", type="primary"):
                success = asyncio.run(self._delete_file(node.get('id', node['path'])))
                
                if success:
                    st.success(f"文件 {node['name']} 已删除")
                    # 清除缓存，刷新文件树
                    if f"file_tree_{project_id}" in st.session_state:
                        del st.session_state[f"file_tree_{project_id}"]
                    # 如果删除的是当前选中文件，清除选中状态
                    if st.session_state.get('selected_file', {}).get('path') == node['path']:
                        st.session_state['selected_file'] = None
                    st.experimental_rerun()
                else:
                    st.error("删除失败")
        
        with col2:
            if st.button("取消", key=f"cancel_delete_{node['path']}"):
                pass
    
    async def _create_file(self, project_id: str, file_path: str, content: str) -> bool:
        """创建文件"""
        
        try:
            result = await self.api_client.create_file(project_id, {
                'path': file_path,
                'content': content
            })
            
            return result['code'] == 200
        
        except Exception as e:
            st.error(f"创建文件失败: {str(e)}")
            return False
    
    async def _delete_file(self, file_id: str) -> bool:
        """删除文件"""
        
        try:
            result = await self.api_client.delete_file(file_id)
            return result['code'] == 200
        
        except Exception as e:
            st.error(f"删除文件失败: {str(e)}")
            return False     
